local skynet = require "skynet"
local filename = "slotmgr.lua"
local filelog = require "filelog"
local queue = require "skynet.queue"
local base = require "base"
local redisdao = require "redisdao"
local tabletool = require "tabletool"
local timetool = require "timetool"
local json = require "cjson"
json.encode_sparse_array(true,1,1)

local SlotTool = require "slottool"
require "cpcqsscenum"

------------
--枚举类

--系统输钱上限基值,默认10万
local SystemLoseLimit_Base = 1000000

--系统输钱上限控制系数
local SystemLoseLimit_Factor = 0.08

--开奖类型
local LotteryType = {
    LOTTERY_TYPE_SYSTEM_WIN = 1,   --系统必赢
    LOTTERY_TYPE_SYSTEM_LOSE = 2,  --系统必输
    LOTTERY_TYPE_NORMAL = 3,       --正常开奖
}

--[[
    重庆时时彩   近 5 期 http://freeagentapi.caim8.com/free?code=ssc_cq 
    重庆时时彩 期号查询 http://freeagentapi.caim8.com/free?code=ssc_cq&qihao=20180422078
--]]
local get_url_address = "http://freeagentapi.caim8.com/free?code=ssc_cq"
----------------------
--倍率列表
local Odds_list = {
    [1101] = 1.95,
    [1102] = 1.95,
    [1103] = 1.95,
    [1104] = 1.95,

    [1201] = 1.95,
    [1202] = 1.95,
    [1203] = 1.95,
    [1204] = 1.95,

    [1301] = 1.95,
    [1302] = 1.95,
    [1303] = 1.95,
    [1304] = 1.95,

    [1401] = 1.95,
    [1402] = 1.95,
    [1403] = 1.95,
    [1404] = 1.95,
}

---当前时间对应期数
local time_qishu = {
    -----
    [1]  = {"23:50:01", "00:30:00"},
    [2]  = {"00:30:01", "00:50:00"},
    [3]  = {"00:50:01", "01:10:00"},
    [4]  = {"01:10:01", "01:30:00"},
    [5]  = {"01:30:01", "01:50:00"},
    [6]  = {"01:50:01", "02:10:00"},
    [7]  = {"02:10:01", "02:30:00"},
    [8]  = {"02:30:01", "02:50:00"},
    [9]  = {"02:50:01", "03:10:00"},
    [10] = {"03:10:01", "07:30:00"},
    [11] = {"07:30:01", "07:50:00"},
    [12] = {"07:50:01", "08:10:00"},
    [13] = {"08:10:01", "08:30:00"},
    [14] = {"08:30:01", "08:50:00"},
    [15] = {"08:50:01", "09:10:00"},
    [16] = {"09:10:01", "09:30:00"},
    [17] = {"09:30:01", "09:50:00"},
    [18] = {"09:50:01", "10:10:00"},
    [19] = {"10:10:01", "10:30:00"},
    [20] = {"10:30:01", "10:50:00"},
    [21] = {"10:50:01", "11:10:00"},
    [22] = {"11:10:01", "11:30:00"},
    [23] = {"11:30:01", "11:50:00"},
    [24] = {"11:50:01", "12:10:00"},
    [25] = {"12:10:01", "12:30:00"},
    [26] = {"12:30:01", "12:50:00"},
    [27] = {"12:50:01", "13:10:00"},
    [28] = {"13:10:01", "13:30:00"},
    [29] = {"13:30:01", "13:50:00"},
    [30] = {"13:50:01", "14:10:00"},
    [31] = {"14:10:01", "14:30:00"},
    [32] = {"14:30:01", "14:50:00"},
    [33] = {"14:50:01", "15:10:00"},
    [34] = {"15:10:01", "15:30:00"},
    [35] = {"15:30:01", "15:50:00"},
    [36] = {"15:50:01", "16:10:00"},
    [37] = {"16:10:01", "16:30:00"},
    [38] = {"16:30:01", "16:50:00"},
    [39] = {"16:50:01", "17:10:00"},
    [40] = {"17:10:01", "17:30:00"},
    [41] = {"17:30:01", "17:50:00"},
    [42] = {"17:50:01", "18:10:00"},
    [43] = {"18:10:01", "18:30:00"},
    [44] = {"18:30:01", "18:50:00"},
    [45] = {"18:50:01", "19:10:00"},
    [46] = {"19:10:01", "19:30:00"},
    [47] = {"19:30:01", "19:50:00"},
    [48] = {"19:50:01", "20:10:00"},
    [49] = {"20:10:01", "20:30:00"},
    [50] = {"20:30:01", "20:50:00"},
    [51] = {"20:50:01", "21:10:00"},
    [52] = {"21:10:01", "21:30:00"},
    [53] = {"21:30:01", "21:50:00"},
    [54] = {"21:50:01", "22:10:00"},
    [55] = {"22:10:01", "22:30:00"},
    [56] = {"22:30:01", "22:50:00"},
    [57] = {"22:50:01", "23:10:00"},
    [58] = {"23:10:01", "23:30:00"},
    [59] = {"23:30:01", "23:50:00"},
}

--系统库存概率表
--S = 库存值
local S_list = {
    [1] = { -- S < -500万
        nohit = 1.00,   --必不中概率
        normal = 0.00,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [2] = { -- -500万<=S<-100万
        nohit = 0.80,   --必不中概率
        normal = 0.20,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [3] = { -- -100万<=S<-20万
        nohit = 0.60,   --必不中概率
        normal = 0.40,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [4] = { -- -20万<=S<-10万
        nohit = 0.30,   --必不中概率
        normal = 0.70,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [5] = { -- -10万<=S<200万
        nohit = 0.00,   --必不中概率
        normal = 1.00,  --正常开奖概率
        hit = 0.00,     --必中概率
    },
    [6] = { -- 200万<=S<1000万
        nohit = 0.00,   --必不中概率
        normal = 0.80,  --正常开奖概率
        hit = 0.20,     --必中概率
    },
    [7] = { -- 1000万<=S<5000万
        nohit = 0.00,   --必不中概率
        normal = 0.60,  --正常开奖概率
        hit = 0.40,     --必中概率
    },
    [8] = { -- 5000万<=S<1亿
        nohit = 0.00,   --必不中概率
        normal = 0.50,  --正常开奖概率
        hit = 0.50,     --必中概率
    },
    [9] = { -- S>=1亿
        nohit = 0.00,   --必不中概率
        normal = 0.40,  --正常开奖概率
        hit = 0.60,     --必中概率
    },
}
--------------------------
--辅助表
--图标概率表，由权重表生成
local Prob_list = nil
--图标总权值,，由权重表生成
local Total_weight = nil
--预存牌型表,每种5种
local Profile_Cards_List = {           
}


function SlotTool.get_prize_ids(points)
    local prize_ids = {}
    if #points ~= 5 then
        return prize_ids
    end
    ----个位
    local genum = points[1]
    if genum >= 0 and genum <= 4 then
        table.insert(prize_ids, 1102)
    elseif genum >= 5 and genum <= 9 then
        table.insert(prize_ids, 1101)
    end
    if genum % 2 == 0 then
        table.insert(prize_ids, 1104)
    elseif genum % 2 == 1 then
        table.insert(prize_ids, 1103)
    end

    ---十位
    local tennum = points[2]
    if tennum >= 0 and tennum <= 4 then
        table.insert(prize_ids, 1202)
    elseif tennum >= 5 and tennum <= 9 then
        table.insert(prize_ids, 1201)
    end
    if tennum % 2 == 0 then
        table.insert(prize_ids, 1204)
    elseif tennum % 2 == 1 then
        table.insert(prize_ids, 1203)
    end

    ---千位
    local thnum = points[4]
    if thnum >= 0 and thnum <= 4 then
        table.insert(prize_ids, 1302)
    elseif thnum >= 5 and thnum <= 9 then
        table.insert(prize_ids, 1301)
    end
    if thnum % 2 == 0 then
        table.insert(prize_ids, 1304)
    elseif thnum % 2 == 1 then
        table.insert(prize_ids, 1303)
    end

    ---万位
    local tthnum = points[5]
    if tthnum >= 0 and tthnum <= 4 then
        table.insert(prize_ids, 1402)
    elseif tthnum >= 5 and tthnum <= 9 then
        table.insert(prize_ids, 1401)
    end
    if tthnum % 2 == 0 then
        table.insert(prize_ids, 1404)
    elseif tthnum % 2 == 1 then
        table.insert(prize_ids, 1403)
    end
    return prize_ids
end
--
--获取开奖类型
--返回 LotteryType类型
--
function SlotTool.get_lottery_type(gamename)
    --获取库存值
    local inventory = SlotTool.get_static_inventory_from_redis(gamename)

    local item = nil
    local s = inventory
    local a = 10000
    if s < -500 * a then
        item = S_list[1]
    elseif s >= -500 * a and s < -100 * a then
        item = S_list[2]
    elseif s >= -100 * a and s < -20 * a  then
        item = S_list[3]
    elseif s >= -20 * a and s < -10 * a then
        item = S_list[4]
    elseif s >= -10 * a and s < 200 * a then
        item = S_list[5]
    elseif s >= 200 * a and s < 1000 * a then
        item = S_list[6]
    elseif s >= 1000 * a and s < 5000 * a then
        item = S_list[7]
    elseif s >= 5000 * a and s < 10000 * a then
        item = S_list[8]
    elseif s >= 10000 * a then
        item = S_list[9]
    end

     --根据概率获取随机开奖类型
    local r = base.get_random(1, 1000)
    local hit = math.floor(item.hit * 1000)
    local nohit = hit + math.floor(item.nohit * 1000)
    local normal = nohit + math.floor(item.normal * 1000) 
    if r <= hit then
        return LotteryType.LOTTERY_TYPE_SYSTEM_LOSE
    elseif r <= nohit then
        return LotteryType.LOTTERY_TYPE_SYSTEM_WIN
    elseif r <= normal then
        return LotteryType.LOTTERY_TYPE_NORMAL
    end
end


--根据随机结果获取额外奖励项
--
function SlotTool.get_ext_prize_item(prize_id)
    
end

--
--保存奖励记录
--
function SlotTool.save_prize_records(gamename, opencard_result)
    local records = {}
    local key = (gamename or "") .. "_prize_records"
    local result,data = redisdao.query_data(".gmmqredis", "get", key)
    if result and data then
        records = json.decode(data) or {}
    end
    
    for _,prize_id in pairs(opencard_result) do
        local id = tostring(prize_id)
        records[id] = (tonumber(records[id]) or 0) + 1
    end
    records.total_count = (tonumber(records.total_count) or 0) + 1
    redisdao.query_data(".gmmqredis", "set", key, json.encode(records))

    ---------------------------------

    --辅助函数1
    local function helper_func(val)
        local cnt = 0
        local tmp = val
        while val >= 10 do
            val = math.floor(val / 10)
            cnt = cnt + 1
        end
        if math.floor(10^cnt) == tmp then
            return true
        end
        return false
    end

    --辅助函数2
    local function func(records)
        local porp_list = {}
        local subprop_list = {}
        local cnt = records.total_count or 0
        if cnt == 0 then
            return
        end

        for k,v in pairs(records) do
            if type(v) ~= "table" and k ~= "total_count" then
                v = tonumber(v) or 0
                porp_list[k] = string.format("%g%%",math.floor(v / cnt * 10000) / 100)
            elseif k == "total_count" then
                porp_list[k] = v
            else
                subprop_list[k] = func(v)
            end
        end
        return porp_list,subprop_list
    end

    --开奖次数每增加10倍，统计一次概率
    if helper_func(records.total_count) then
        local porp_list,subprop_list = func(records)
        filelog.sys_obj("prop_list", records.total_count, porp_list, "=================\n", subprop_list)
    end
    ---------------

    return true
end

--
--创建格式化赔率列表
--
function SlotTool.create_format_odds_list()
    local fmt_odds_list = {}

    for id,odds_list in pairs(Odds_list) do
        for cardstype,odds in pairs(odds_list) do
            if type(odds) == "table" then
                for i = 0,9 do
                    local real_odds = odds[i] or odds[1] or 2
                    local val = tonumber(id) * 10000 + cardstype * 1000 + i * 100 + tonumber(real_odds)
                    table.insert(fmt_odds_list,val)
                end
            else
                for i = 0,9 do
                    local val = tonumber(id) * 10000 + cardstype * 1000 + i * 100 + tonumber(odds)
                    table.insert(fmt_odds_list,val)
                end
            end
        end
    end
    
    return fmt_odds_list
end


function SlotTool.get_curr_qishu_by_time(time_now)
    local curr_qishu = 0
    local time_date1 = os.date("%Y-%m-%d", time_now) .. " " .. time_qishu[1][1]
    local time_value1 = timetool.datestr_to_time(time_date1)
    local time_date2 = os.date("%Y-%m-%d", time_now) .. " " .. time_qishu[1][2]
    local time_value2 = timetool.datestr_to_time(time_date2)
    if time_now >= time_value1 or time_now <= time_value2 then
        curr_qishu = 1
        return curr_qishu
    else
        local curr_qishu = 0
        for index, qishudetail in ipairs(time_qishu) do
            local qishu_begin = timetool.datestr_to_time(os.date("%Y-%m-%d", time_now) .. " " .. qishudetail[1])
            local qishu_end = timetool.datestr_to_time(os.date("%Y-%m-%d", time_now) .. " " .. qishudetail[2])
            if time_now >= qishu_begin and time_now <= qishu_end then
                curr_qishu = index
                break
            end
        end
        return curr_qishu
    end 
end

-------------------------------
----------
--外部接口

local CMD = {}

local cs = queue()

function CMD.get_odds_list()
    return Odds_list
end


function CMD.get_lottery_result(gamename)
    local lottery_result = {
        points = {},
        prize_ids = {},
    }
    for i = 1, 5 do
        local getpoint = base.get_random(0,9)
        table.insert(lottery_result.points, getpoint)
    end

    lottery_result.prize_ids = SlotTool.get_prize_ids(lottery_result.points)
    
    return lottery_result
end

function CMD.get_lottery_result_by_points(points)
    local lottery_result = {
        points = {},
        prize_ids = {},
    }
    lottery_result.points = tabletool.deepcopy(points)
    lottery_result.prize_ids = SlotTool.get_prize_ids(lottery_result.points)
    
    return lottery_result
end

function CMD.get_lottery_result_by_qihao(curr_qishu)
    local get_result_url = get_url_address .. "&qihao=" .. tostring(curr_qishu)
    --local status, result = skynet.pcall(skynet.call, ".httpservice", "lua", "send_http_request", 0, get_result_url)
    local status, request_status, result = skynet.pcall(skynet.call, ".webclient", "lua", "request", get_result_url)
    if not status or not request_status then
        return false
    else
        return result
    end
end

function CMD.get_recent_lottery_result()
    --local status, result = skynet.pcall(skynet.call, ".httpservice", "lua", "send_http_request", 0, get_url_address)

    --使用非阻塞的http请求
    local status, request_status, result = skynet.pcall(skynet.call, ".webclient", "lua", "request", get_url_address)
    ---filelog.sys_error("------get_recent_lottery_result------", status, request_status, result)
    if not status or not request_status then
        return false
    else
        return result
    end
end

function CMD.send_player_changes(rid_values, comment)
    return SlotTool.send_player_changes(rid_values, comment)
end


--
--保存奖励记录
--
function CMD.save_prize_records(gamename, opencard_result)
  return cs(SlotTool.save_prize_records,gamename,opencard_result)
end

--
--处理庄家收益
--
function CMD.handle_banker_profit(ganmename, total_bet_num, player_win_num)
    local banker_win = total_bet_num - player_win_num
    return banker_win
end
--
--设置系统输钱上限
--
function CMD.set_system_lose_limit(loselimit_base, loselimit_factor)
    loselimit_base = loselimit_base or 0
    loselimit_factor = loselimit_factor or 0.02
    if loselimit_base < 0 or loselimit_factor < 0 then
        return false
    end
    SystemLoseLimit_Base = loselimit_base
    SystemLoseLimit_Factor = loselimit_factor

    return true
end

--
--获取格式化赔率列表
--
function CMD.get_format_odds_list()
    return SlotTool.create_format_odds_list()
end

--
--处理结算结果
--@total_change 总变化值
--@total_water  总流水值
--@total_bet    玩家总下注
--
function CMD.handle_balance_result(gamename, total_change, total_water, total_bet, comment)
    local tax_rate = SlotTool.get_tax_rate_from_redis(gamename)
    local profit_val = math.floor(total_bet * tax_rate * 100) / 100
    local inventory_val = -total_change

    --更新收益值
    local result1 = SlotTool.update_system_profit(gamename, profit_val, comment)
    if result1 then
        inventory_val = inventory_val - profit_val
    end

    --更新库存值，扣除抽水
    local service_fee_rate = SlotTool.get_service_fee_rate_from_redis(gamename)
    local service_fee_val = math.floor(total_water * service_fee_rate * 100) / 100
    inventory_val = inventory_val - service_fee_val

    return SlotTool.update_system_inventory(gamename, inventory_val, comment)
end

function CMD.update_system_profit(gamename, profit_val, comment)
    return SlotTool.update_system_profit(gamename, profit_val, comment)
end

function CMD.update_system_inventory(gamename, inventory_val, comment)
    return SlotTool.update_system_inventory(gamename, inventory_val, comment)
end

function CMD.get_system_inventory(gamename)
    return SlotTool.get_inventory_from_redis(gamename)
end
--
--获取抽水率
--
function CMD.get_service_fee_rate(gamename)
    local service_fee_rate = 0.000   --默认抽水率0.025*2
    local key = (gamename or "") .. "_service_fee_rate"
    local result, result_data = redisdao.query_data(".gmmqredis", "get", key)
    if result and result_data then
        service_fee_rate = tonumber(result_data) or 0.025
        if service_fee_rate > 0.5 or service_fee_rate < 0.01 then
            service_fee_rate = 0.000
        end
    end
    return service_fee_rate
end

function CMD.get_curr_to_number(time_now)
    local curr_qishu = SlotTool.get_curr_qishu_by_time(time_now)
    return curr_qishu
end

function CMD.get_curr_qishu_string(time_now)
    local curr_qishu = SlotTool.get_curr_qishu_by_time(time_now)
    local time_date1 = os.date("%Y-%m-%d", time_now) .. " " .. time_qishu[1][1]
    local time_value1 = timetool.datestr_to_time(time_date1)
    local time_date2 = os.date("%Y-%m-%d", time_now) .. " " .. time_qishu[1][2]
    local time_value2 = timetool.datestr_to_time(time_date2)
    if time_now >= time_value1 then
        local now_time_string = os.date("%Y-%m-%d %H:%M:%S", time_now)
        local now_qishu_time = timetool.datestr_to_time(now_time_string, 1, "DAY")
        return os.date("%Y%m%d", now_qishu_time) .. "-" .. string.format("%03d", curr_qishu)
    elseif time_now <= time_value2 then
        return os.date("%Y%m%d", time_now) .. "-" .. string.format("%03d", curr_qishu)
    else
        return os.date("%Y%m%d", time_now) .. "-" .. string.format("%03d", curr_qishu)
    end
end

function CMD.get_last_qishu(time_now)
    local curr_qishu = SlotTool.get_curr_qishu_by_time(time_now)
    if curr_qishu == 1 then
        local now_time_string = os.date("%Y-%m-%d %H:%M:%S", time_now)
        local last_qishu_date = timetool.datestr_to_time(now_time_string, -1, "DAY")
        return os.date("%Y%m%d", last_qishu_date) .. "-059"
    else
        local now_time_string = os.date("%Y-%m-%d %H:%M:%S", time_now)
        local last_qishu_date = timetool.datestr_to_time(now_time_string, -1, "DAY")
        return os.date("%Y%m%d", time_now) .. "-" .. string.format("%03d", curr_qishu - 1)
    end
end

function CMD.get_stop_bet_time(time_now)
    local curr_qishu = SlotTool.get_curr_qishu_by_time(time_now)
    local curr_qishu_area = time_qishu[curr_qishu]
    if curr_qishu == 1 then
        local time_date1 = os.date("%Y-%m-%d", time_now) .. " " .. time_qishu[1][1]
        local time_value1 = timetool.datestr_to_time(time_date1)
        local time_date2 = os.date("%Y-%m-%d", time_now) .. " " .. time_qishu[1][2]
        local time_value2 = timetool.datestr_to_time(time_date2)
        if time_now >= time_value1 then
            local now_time_string = os.date("%Y-%m-%d %H:%M:%S", time_now)
            local now_qishu_time = timetool.datestr_to_time(now_time_string, 1, "DAY")
            local now_date = os.date("%Y-%m-%d", now_qishu_time) .. " " .. curr_qishu_area[2]
            return timetool.datestr_to_time(now_date, -ECQSSCFORTimemin, "MINUTE")
        elseif time_now <= time_value2 then
            local now_date = os.date("%Y-%m-%d", time_now) .. " " .. curr_qishu_area[2]
            return timetool.datestr_to_time(now_date, -ECQSSCFORTimemin, "MINUTE")
        end
    else
        local now_date = os.date("%Y-%m-%d", time_now) .. " " .. curr_qishu_area[2]
        ---filelog.sys_error("-----------now_date---------", now_date)
        return timetool.datestr_to_time(now_date, -ECQSSCFORTimemin, "MINUTE")
    end
end

function CMD.get_open_award_time(stop_bet_time)
    return stop_bet_time + ECQSSCFORTimesecond
end

local function init()
    CMD.get_recent_lottery_result()
end

-------------------
--
skynet.start(function()
    init()
    skynet.dispatch("lua",function(session, source, cmd, ...)
        local f = CMD[cmd]
        if f then
            skynet.retpack(f(...))
        else
            skynet.retpack()
        end
    end)
end)